package priv.menghan.happy.learning.generator;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;

import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * mybatis-plus代码生成器
 *
 * @author Monika
 * @version 1.0
 * &#064;Since  2025/6/8
 */
public class CodeGenerator {

	// 多个表名用逗号隔开
	static String tableNames = "user_role,user_info,role";
	static String moduleName = "user";
	static String childModuleSuffix = "happy-learning-user";
	// 模板路径，默认是/templates/
	static String templatesPath = "/my_templates/";
	static String projectName = "happy-learning";
	static String projectCode = "happy.learning";
	static String groupId = "priv.menghan";

	static String author = "Monika";
	static String url = "jdbc:mysql://localhost:3306/happy_learning?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
	static String driverName = "com.mysql.cj.jdbc.Driver";
	static String userName = "root";
	static String password = "yourselfpasswprd";

	/**
	 * 自定义输出配置列表，按配置顺序输出
	 *
	 * @return
	 */
	static List<FileOutConfig> getFileOutConfigList() {
		List<FileOutConfig> focList = new ArrayList<>();
		//
		// focList.add(getFileOutConfig("entity.java.vm", "dao/entity", "Entity", StringPool.DOT_JAVA));
		//
		// focList.add(getFileOutConfig("mapper.java.vm", "dao/mapper", "Mapper", StringPool.DOT_JAVA));
		focList.add(getFileOutConfig("mapper.xml.vm", "dao/mapper/impl", "MapperImpl", StringPool.DOT_XML));
		//
		// focList.add(getFileOutConfig("repository.java.vm", "dao/repository", "Repository",
		// 		StringPool.DOT_JAVA));
		// focList.add(getFileOutConfig("repositoryImpl.java.vm", "dao/repository/impl", "RepositoryImpl",
		// 		StringPool.DOT_JAVA));
		//
		// focList.add(getFileOutConfig("req.java.vm", "req", "Req", StringPool.DOT_JAVA));
		// focList.add(getFileOutConfig("resp.java.vm", "resp", "Resp", StringPool.DOT_JAVA));
		//
		// focList.add(getFileOutConfig("service.java.vm", "service", "Service", StringPool.DOT_JAVA));
		// focList.add(getFileOutConfig("serviceImpl.java.vm", "service/impl", "ServiceImpl", StringPool.DOT_JAVA));
		// focList.add(getFileOutConfig("controller.java.vm", "controller", "Controller", StringPool.DOT_JAVA));
		// focList.add(getFileOutConfig("mapStruct.java.vm", "mapstruct", "MapStruct", StringPool.DOT_JAVA));

		return focList;
	}

	public static void main(String[] strings) {
		try {
			URL resourceUrl = CodeGenerator.class.getClassLoader().getResource("my_templates");
			if (resourceUrl == null) {
				System.err.println("❌ 资源路径不存在，请确认路径是否正确");
				return;
			} else {
				System.out.println("✅ 资源路径为：" + resourceUrl.getPath());
			}

			// 代码生成器
			AutoGenerator mpg = new AutoGenerator();
			// 全局配置
			mpg.setGlobalConfig(getGlobalConfig());
			// 数据源配置
			mpg.setDataSource(getDataSourceConfig());
			// 包配置
			mpg.setPackageInfo(getPackageConfig());
			// 自定义配置
			mpg.setCfg(getInjectionConfig());
			// 配置默认模板配置
			mpg.setTemplate(getTemplateConfig());
			// 策略配置
			mpg.setStrategy(getStrategy());
			mpg.setTemplateEngine(new VelocityTemplateEngine());
			String projectPath = System.getProperty("user.dir");
			System.out.println("项目路径: " + projectPath);

			mpg.execute();
		} catch (Exception e) {
			System.err.println("❌ 代码生成失败！");
			e.printStackTrace();
		}
	}

	/**
	 * 全局配置
	 *
	 * @return
	 */
	static GlobalConfig getGlobalConfig() {
		GlobalConfig gc = new GlobalConfig();
		// 自定义输出路径注释此处
		// gc.setOutputDir(projectPath + "/src/main/java");
		gc.setAuthor(author);
		// 是否打开输出的目录，默认true
		gc.setOpen(false);
		// 覆盖已有的文件，默认false(第一次生成时放开)
		gc.setFileOverride(true);
		gc.setBaseResultMap(true);
		gc.setBaseColumnList(true);
		//  设置日期类型为Date(若不设置时间类型都会变成LocalDateTime部分连接池例如druid是无法识别的)
		gc.setDateType(DateType.ONLY_DATE);
		return gc;
	}

	/**
	 * 数据源
	 *
	 * @return
	 */
	static DataSourceConfig getDataSourceConfig() {
		DataSourceConfig dsc = new DataSourceConfig();
		dsc.setUrl(url);
		dsc.setDriverName(driverName);
		dsc.setUsername(userName);
		dsc.setPassword(password);
		return dsc;
	}

	/**
	 * 包配置
	 */
	static PackageConfig getPackageConfig() {
		PackageConfig pc = new PackageConfig();
		// 禁用父包拼接
		pc.setParent(null);
		// 禁用模块名拼接
		pc.setModuleName(null);
		// 基础包路径
		String basePackage = groupId + "." + projectCode + "." + moduleName;

		pc.setEntity(basePackage + ".dao.entity");
		pc.setMapper(basePackage + ".dao.mapper");
		pc.setXml(basePackage + ".dao.mapper.impl");
		pc.setService(basePackage + ".service");
		pc.setServiceImpl(basePackage + ".service.impl");
		pc.setController(basePackage + ".controller");

		return pc;
	}


	/**
	 * 自定义配置
	 */
	static InjectionConfig getInjectionConfig() {
		List<FileOutConfig> fileOutConfigList = getFileOutConfigList();
		InjectionConfig cfg = new InjectionConfig() {
			@Override
			public void initMap() {
				Map<String, Object> map = new HashMap<>();
				String basePackage = groupId + "." + projectCode + "." + moduleName;
				// 包路径
				map.put("Entity", basePackage + ".dao.entity");
				map.put("Mapper", basePackage + ".dao.mapper");
				map.put("Repository", basePackage + ".dao.repository");
				map.put("RepositoryImpl", basePackage + ".dao.repository.impl");
				map.put("Service", basePackage + ".service");
				map.put("ServiceImpl", basePackage + ".service.impl");
				map.put("Controller", basePackage + ".controller");
				map.put("Req", basePackage + ".req");
				map.put("Resp", basePackage + ".resp");
				map.put("ModuleName", moduleName);
				map.put("MapStruct", basePackage + ".mapstruct");

				// 时间戳
				map.put("time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
				this.setMap(map);
			}
		};

		cfg.setFileOutConfigList(fileOutConfigList);
		return cfg;
	}


	/**
	 * 配置默认模板配置
	 */
	static TemplateConfig getTemplateConfig() {
		return new TemplateConfig()
				.setEntity(null)
				.setMapper(null)
				.setXml(null)
				.setService(null)
				.setServiceImpl(null)
				.setController(null);
	}

	/**
	 * 策略配置
	 */
	static StrategyConfig getStrategy() {
		StrategyConfig strategy = new StrategyConfig();
		strategy.setNaming(NamingStrategy.underline_to_camel);
		strategy.setColumnNaming(NamingStrategy.underline_to_camel);
		// 是否为lombok模型，默认为false
		strategy.setEntityLombokModel(true);
		// 前后端分离时可开启
		strategy.setRestControllerStyle(true);
		// 数据库表，多表用逗号隔开
		// strategy.setInclude(scanner("table name").split(","));
		strategy.setInclude(tableNames.split(","));
		// RequestMapping驼峰转连字符

		// strategy.setControllerMappingHyphenStyle(true);
		// 生成实体时生成生成数据库字段注解
		strategy.setEntityTableFieldAnnotationEnable(true);
		return strategy;
	}

	/**
	 * 自定义输出配置
	 *
	 * @param templateFileName 模板文件名
	 * @param outPath          相对路径
	 * @param fileSuffix       文件后缀
	 * @param outputFileType   输出文件类型
	 * @return FileOutConfig
	 */
	static FileOutConfig getFileOutConfig(String templateFileName, String outPath,
										  String fileSuffix, String outputFileType) {
		return new FileOutConfig(templatesPath + templateFileName) {
			@Override
			public String outputFile(TableInfo tableInfo) {
				String fileName = tableInfo.getEntityName() + ("Entity".equals(fileSuffix) ? "" : fileSuffix);
				// 基础包路径
				String basePackage = groupId + "." + projectCode + "." + moduleName;
				String projectPath = System.getProperty("user.dir");
				// System.out.println("项目路径: " + projectPath);
				// 输出文件位置
				String outputFilePath = projectPath + "/" + childModuleSuffix + "/src/main/java/" + basePackage.replace(".", "/");

				String outputFileName = outputFilePath + "/" + outPath + "/" + fileName + outputFileType;
				// System.out.println("即将生成文件: " + outputFileName);
				return outputFileName;
			}
		};
	}

}
